﻿using ClassifiedAds.IdentityServer.Models.IdentityResourceModels;
using Duende.IdentityServer.EntityFramework.DbContexts;
using Duende.IdentityServer.EntityFramework.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;

namespace ClassifiedAds.IdentityServer.Controllers;

public class IdentityResourceController : Controller
{
    private readonly ConfigurationDbContext _configurationDbContext;

    public IdentityResourceController(ConfigurationDbContext configurationDbContext)
    {
        _configurationDbContext = configurationDbContext;
    }

    public IActionResult Index()
    {
        var itentities = _configurationDbContext.IdentityResources.ToList();
        return View(itentities.ToModels().ToList());
    }

    public IActionResult Add()
    {
        return View(nameof(Edit), new IdentityResourceModel());
    }

    public IActionResult Edit(int id)
    {
        var identity = _configurationDbContext.IdentityResources
            .Include(x => x.UserClaims)
            .FirstOrDefault(x => x.Id == id);
        return View(identity.ToModel());
    }

    [HttpPost]
    public IActionResult Edit(IdentityResourceModel model)
    {
        IdentityResource identity;
        if (model.Id == 0)
        {
            identity = new IdentityResource
            {
                UserClaims = new List<IdentityResourceClaim>(),
            };
            _configurationDbContext.IdentityResources.Add(identity);
        }
        else
        {
            identity = _configurationDbContext.IdentityResources
                .Include(x => x.UserClaims)
                .FirstOrDefault(x => x.Id == model.Id);
            identity.UserClaims.Clear();
        }

        model.UpdateEntity(identity);

        if (!string.IsNullOrEmpty(model.UserClaimsItems))
        {
            model.UserClaims = JsonSerializer.Deserialize<List<string>>(model.UserClaimsItems);

            identity.UserClaims.AddRange(model.UserClaims.Select(x => new IdentityResourceClaim
            {
                Type = x,
            }));
        }

        _configurationDbContext.SaveChanges();

        return RedirectToAction(nameof(Edit), new { id = identity.Id });
    }

    public IActionResult Delete(int id)
    {
        var identity = _configurationDbContext.IdentityResources
            .Include(x => x.UserClaims)
            .FirstOrDefault(x => x.Id == id);
        return View(identity.ToModel());
    }

    [HttpPost]
    public IActionResult Delete(IdentityResourceModel model)
    {
        var identity = _configurationDbContext.IdentityResources
            .FirstOrDefault(x => x.Id == model.Id);

        _configurationDbContext.IdentityResources.Remove(identity);
        _configurationDbContext.SaveChanges();

        return RedirectToAction(nameof(Index));
    }

    public IActionResult Properties(int id)
    {
        var identity = _configurationDbContext.IdentityResources
            .Include(x => x.Properties)
            .FirstOrDefault(x => x.Id == id);
        return View(PropertiesModel.FromEntity(identity));
    }

    [HttpPost]
    public IActionResult AddProperty(PropertiesModel model)
    {
        var identity = _configurationDbContext.IdentityResources
            .Include(x => x.Properties)
            .FirstOrDefault(x => x.Id == model.IdentityResourceId);

        identity.Properties.Add(new IdentityResourceProperty
        {
            Key = model.Key,
            Value = model.Value,
        });

        _configurationDbContext.SaveChanges();

        return RedirectToAction(nameof(Properties), new { id = identity.Id });
    }

    [HttpGet]
    public IActionResult DeleteProperty(int id)
    {
        var prop = _configurationDbContext.Set<IdentityResourceProperty>()
            .Include(x => x.IdentityResource)
            .FirstOrDefault(x => x.Id == id);
        return View(IdentityResourcePropertyModel.FromEntity(prop));
    }

    [HttpPost]
    public IActionResult DeleteProperty(IdentityResourcePropertyModel model)
    {
        var identity = _configurationDbContext.IdentityResources
                        .Include(x => x.Properties)
                        .FirstOrDefault(x => x.Id == model.IdentityResource.Id);
        var prop = identity.Properties.FirstOrDefault(x => x.Id == model.Id);
        identity.Properties.Remove(prop);
        _configurationDbContext.SaveChanges();

        return RedirectToAction(nameof(Properties), new { id = identity.Id });
    }

    public IActionResult GetClaims()
    {
        // http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
        var standardClaims = new List<string>
        {
            "name",
            "given_name",
            "family_name",
            "middle_name",
            "nickname",
            "preferred_username",
            "profile",
            "picture",
            "website",
            "gender",
            "birthdate",
            "zoneinfo",
            "locale",
            "address",
            "updated_at",
        };

        return Ok(standardClaims);
    }
}